防抖(Debounce)与节流(Throttle) 
一、核心原理对比 
| 特性 | 防抖(Debounce) | 节流(Throttle) | 
|---|---|---|
| 核心思想 | "等你说完我再响应" | "按固定节奏响应" | 
| 触发策略 | 延迟执行,期间新触发会重置计时 | 固定时间间隔内只执行一次 | 
| 类比场景 | 电梯门(最后一个人进后关门) | 机枪扫射(按固定频率发射) | 
| 典型应用 | 搜索联想、窗口 resize 结束监听 | 滚动加载、高频点击按钮 | 
二、手写实现代码 
1. 防抖函数(基础版 + 增强版) 
js
function debounce(func, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
javascript
/**
 * 防抖函数
 * @param {Function} fn - 目标函数
 * @param {number} delay - 延迟时间(ms)
 * @param {boolean} immediate - 是否立即执行
 * @returns {Function} 防抖处理后的函数
 */
function debounce(fn, delay = 300, immediate = false) {
  let timer = null;
  
  return function(...args) {
    const context = this;
    
    // 清除已有定时器
    if (timer) clearTimeout(timer);
    
    // 立即执行模式
    if (immediate && !timer) {
      fn.apply(context, args);
    }
    
    timer = setTimeout(() => {
      timer = null;
      if (!immediate) {
        fn.apply(context, args);
      }
    }, delay);
  };
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2. 节流函数(时间戳 + 定时器双模式) 
js
function throttle(func, delay) {
  let lastTime = 0;
  return function(...args) {
    const now = new Date().getTime();
    if (now - lastTime >= delay) {
      func.apply(this, args);
      lastTime = now;
    }
  };
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
javascript
/**
 * 节流函数
 * @param {Function} fn - 目标函数
 * @param {number} interval - 时间间隔(ms)
 * @param {boolean} trailing - 是否在间隔末尾执行
 * @returns {Function} 节流处理后的函数
 */
function throttle(fn, interval = 300, trailing = true) {
  let lastTime = 0;
  let timer = null;
  
  return function(...args) {
    const context = this;
    const now = Date.now();
    
    // 时间差计算
    const remaining = interval - (now - lastTime);
    
    if (remaining <= 0) {
      // 到达间隔时间立即执行
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      fn.apply(context, args);
      lastTime = now;
    } else if (trailing && !timer) {
      // 间隔末尾补发执行
      timer = setTimeout(() => {
        fn.apply(context, args);
        lastTime = Date.now();
        timer = null;
      }, remaining);
    }
  };
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
三、使用示例 
javascript
// 防抖应用:搜索框联想
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function(e) {
  console.log('搜索关键词:', e.target.value);
}, 500));
// 节流应用:滚动加载
window.addEventListener('scroll', throttle(function() {
  console.log('当前滚动位置:', window.scrollY);
}, 1000));1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
四、实现关键点解析 
| 功能 | 防抖实现要点 | 节流实现要点 | 
|---|---|---|
| 定时器管理 | 每次触发重置定时器 | 通过时间戳判断间隔,定时器用于补发执行 | 
| 上下文绑定 | 使用 apply保持 this 指向正确 | 同上 | 
| 参数传递 | ...args保留所有原始参数 | 同上 | 
| 边缘情况处理 | 处理立即执行模式 | 处理首尾触发模式 | 
五、高级特性扩展 
- 取消功能 javascript- // 防抖增加取消方法 function debounce(...) { const debounced = function(...args) { ... }; debounced.cancel = () => { clearTimeout(timer); timer = null; }; return debounced; }1
 2
 3
 4
 5
 6
 7
 8
 9
- 返回值处理 
 (注:异步函数无法直接返回结果,可通过回调或 Promise 处理)
- RAF 节流 javascript- // 使用 requestAnimationFrame 实现动画节流 function throttleRAF(fn) { let ticking = false; return function(...args) { if (!ticking) { requestAnimationFrame(() => { fn.apply(this, args); ticking = false; }); ticking = true; } }; }1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
总结 
- 防抖:高频事件结束后触发,避免重复执行(如输入验证)
- 节流:高频事件按节奏触发,保障最低执行频率(如滚动计算)
- 生产建议:直接使用 Lodash 的 _.debounce和_.throttle(已处理大量边界情况)